package ar.com.uade.administradorsiembra.persistencia;

import java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import ar.com.uade.administradorsiembra.common.ContextoTransaccional;
import ar.com.uade.administradorsiembra.modelo.Cereal;
import ar.com.uade.administradorsiembra.modelo.CerealFino;
import ar.com.uade.administradorsiembra.modelo.CerealGrueso;
import ar.com.uade.administradorsiembra.modelo.Mineral;
import ar.com.uade.administradorsiembra.modelo.exceptions.TransaccionException;

public class CerealMapper extends Mapper<Cereal> {
	@Override
	public boolean guardar(Cereal cereal) {
		
		int resultado = 0;
		this.logger.info("Guardando el siguiente cereal: " + cereal);
		
		if(cereal.getId() == null){
			ContextoTransaccional contexto = null;
			
			try {
				contexto = super.administradorTransaccional.crearContexto(true);			
				
				resultado = guardarCerealContexto(cereal, contexto.getConexionActual());
				
			} catch (Exception te) {
				this.logger.error("Error al guardar el cereal. " + te.getMessage());
			} finally {
				contexto.liberarConexion();
			}
			
			return resultado > 0;
		}
		else{
			return this.modificar(cereal);
		}
	}

	private int guardarCerealContexto(Cereal cereal, Connection conn) {
		int resultado = 0;
		String query = "INSERT INTO cereal (codigo, fechaDesde, fechaHasta, rendimiento, mineralPrincipalId, eliminado, tipoCereal, desperdicio, descripcion) VALUES (?,?,?,?,?,?,?,?,?)";		
		List<Object> parametros = new ArrayList<Object>();
		
		parametros.add(cereal.getCodigo());
		parametros.add(new Date(cereal.getFechaDesde().getTime()));
		parametros.add(new Date(cereal.getFechaHasta().getTime()));
		parametros.add(cereal.getRendimiento());
		parametros.add(cereal.getMineralPrincipal().getId());
		parametros.add(cereal.estaEliminado());
		parametros.add(cereal.getTipoCereal());
		
		
		if(cereal instanceof  CerealGrueso){
			CerealGrueso cerealAux = (CerealGrueso) cereal;
			parametros.add(cerealAux.getDesperdicio());
			
		}
		else parametros.add(0);
		
		parametros.add(cereal.getDescripcion());
		
		try {
			resultado = this.executeUpdate(query, parametros, conn);
			this.logger.info("Se guardo el cereal en forma exitosa.");
		} catch (SQLException e) {
			this.logger.error("Error al guardar el Cereal. " + e.getMessage());
		}
		return resultado;
	}

	@Override
	public Cereal buscarPorId(Integer id) {
		
		this.logger.info("Buscando cereal por id: " + id);
		
		Cereal cereal = null;
		ContextoTransaccional contexto = null;
		
		try {
			contexto = super.administradorTransaccional.crearContexto(true);		
			
			String query = "SELECT id, codigo, fechaDesde, fechaHasta, rendimiento, mineralPrincipalId, eliminado, tipoCereal, desperdicio, descripcion FROM cereal where id = ? and eliminado = 0";
			List<Object> parametros = new ArrayList<Object>();
			
			parametros.add(id);
			
			ResultSet rs;
			
			try {				
				rs = this.executeQuery(query, parametros, contexto.getConexionActual());

				if(rs.next()){
					
					Mineral mineral = null;
					MineralMapper mineralEntity = new MineralMapper();
					mineral = mineralEntity.buscarPorId(rs.getInt("mineralPrincipalId"));
										
					if(0 == rs.getInt("tipoCereal")){
							 
						cereal = new CerealFino(rs.getInt("id"), rs.getInt("codigo"), rs.getString("descripcion"), rs.getDate("fechaDesde"), rs.getDate("fechaHasta"), rs.getFloat("rendimiento"), mineral, rs.getBoolean("eliminado"));
					}
					else{
						cereal = new CerealGrueso(rs.getInt("id"), rs.getInt("codigo"), rs.getString("descripcion"), rs.getDate("fechaDesde"), rs.getDate("fechaHasta"), rs.getFloat("rendimiento"), mineral, rs.getBoolean("eliminado"),rs.getFloat("desperdicio"));
					}
					this.logger.info("cereal encontrado: " + cereal);			
				}			
			} catch (SQLException e) {
				this.logger.error("Error al buscar el cereal. " + e.getMessage());
			}
		} catch (TransaccionException te) {
			this.logger.error("Error al buscar el cereal. " + te.getMessage());
		} finally {
			contexto.liberarConexion();
		}
	
		return cereal;
	}

	@Override
	public boolean modificar(Cereal cereal) {
        
		this.logger.error("Voy a modificar el cereal: " + cereal);
		
		int resultado = 0;
		ContextoTransaccional contexto = null;
		
		try {
			contexto = super.administradorTransaccional.crearContexto(true);
			
			StringBuffer query = new StringBuffer();
			query.append("UPDATE cereal ");
			query.append("SET codigo = ?  , ");
			query.append("fechaDesde = ? , ");
			query.append("fechaHasta = ? , ");
			query.append("rendimiento = ? , ");
			query.append("mineralPrincipalId = ? , ");
			query.append("eliminado = ? , ");
			query.append("tipoCereal = ? , ");
			query.append("desperdicio = ? , ");
			query.append("descripcion = ? ");
			query.append("WHERE id = ? ");
			
			List<Object> parametros = new ArrayList<Object>();
			
			parametros.add(cereal.getCodigo());
			parametros.add(new Date(cereal.getFechaDesde().getTime()));
			parametros.add(new Date(cereal.getFechaHasta().getTime()));
			parametros.add(cereal.getRendimiento());
			parametros.add(cereal.getMineralPrincipal().getId());
			parametros.add(cereal.estaEliminado());
			parametros.add(cereal.getTipoCereal());
			
			if(cereal instanceof  CerealGrueso){
				CerealGrueso cerealAux = (CerealGrueso) cereal;
				parametros.add(cerealAux.getDesperdicio());
				
			}
			else parametros.add(0);
			parametros.add(cereal.getDescripcion());
			parametros.add(cereal.getId());
			
			
			try {			
				resultado = this.executeUpdate(query.toString(), parametros, contexto.getConexionActual());					
			} catch (SQLException e) {
				this.logger.error("Error al modificar el cereal. " + e.getMessage());
			}
		} catch (TransaccionException te) {
			this.logger.error("Error al buscar el cereal. " + te.getMessage());
		} finally {
			contexto.liberarConexion();
		}	
		
		return resultado > 0;
	}

	@Override
	public boolean borrar(Cereal instancia) {
		// TODO Auto-generated method stub
		instancia.setEliminado(true);
		return modificar(instancia);
	}

	@Override
	public List<Cereal> buscarTodos() {
		
		this.logger.info("Buscando todos los cereales");
		
		List<Cereal> resultado = new ArrayList<Cereal>();
		ContextoTransaccional contexto = null;
		
		try {
			contexto = super.administradorTransaccional.crearContexto(true);			
			
			String query = "SELECT id, codigo, fechaDesde, fechaHasta, rendimiento, mineralPrincipalId, eliminado, tipoCereal, desperdicio, descripcion FROM cereal where eliminado = 0 ";
			List<Object> parametros = new ArrayList<Object>();
			ResultSet rs;
			
			try {
				
				rs = this.executeQuery(query, parametros, contexto.getConexionActual());
				
				while(rs.next()){
				
						
					Mineral mineral = null;
					MineralMapper mineralEntity = new MineralMapper();
					mineral = mineralEntity.buscarPorId(rs.getInt("mineralPrincipalId"));
					Cereal cereal = null;				
					if(0 == rs.getInt("tipoCereal")){
							 
						cereal = new CerealFino(rs.getInt("id"), rs.getInt("codigo"), rs.getString("descripcion"), rs.getDate("fechaDesde"), rs.getDate("fechaHasta"), rs.getFloat("rendimiento"), mineral, rs.getBoolean("eliminado"));
					}
					else{
						cereal = new CerealGrueso(rs.getInt("id"), rs.getInt("codigo"), rs.getString("descripcion"), rs.getDate("fechaDesde"), rs.getDate("fechaHasta"), rs.getFloat("rendimiento"), mineral, rs.getBoolean("eliminado"),rs.getFloat("desperdicio"));
					}
					resultado.add(cereal);
					this.logger.info("Cereal encontrado: " + mineral);			
				}
							
			} catch (SQLException e) {
				this.logger.error("Error al buscar el Cereal. " + e.getMessage());
			}
		} catch (TransaccionException te) {
			this.logger.error("Error al buscar el Cereal. " + te.getMessage());
		} finally {
			contexto.liberarConexion();
		}
		
		return resultado;
	}
	
	public List<Cereal> buscarPorPropiedades(Integer tipoCereal, Mineral mineral) {
		
		this.logger.info("Buscando cereal por tipoCereal y mineral: " + tipoCereal + ", " + mineral.getNombre());
		List<Cereal> resultado = new ArrayList<Cereal>();
		
		Cereal cereal = null;
		ContextoTransaccional contexto = null;
		
		try {
			contexto = super.administradorTransaccional.crearContexto(true);		
			
			String query = "SELECT id, codigo, fechaDesde, fechaHasta, rendimiento, mineralPrincipalId, eliminado, tipoCereal, desperdicio, descripcion FROM cereal where tipoCereal = ? and mineralPrincipalId = ? and eliminado = 0";
			List<Object> parametros = new ArrayList<Object>();
			
			parametros.add(tipoCereal);
			parametros.add(mineral.getId());
			
			ResultSet rs;
			
			try {				
				rs = this.executeQuery(query, parametros, contexto.getConexionActual());

				while(rs.next()){
											
					if(0 == rs.getInt("tipoCereal")){
							 
						cereal = new CerealFino(rs.getInt("id"), rs.getInt("codigo"), rs.getString("descripcion"), rs.getDate("fechaDesde"), rs.getDate("fechaHasta"), rs.getFloat("rendimiento"), mineral, rs.getBoolean("eliminado"));
					}
					else{
						cereal = new CerealGrueso(rs.getInt("id"), rs.getInt("codigo"), rs.getString("descripcion"), rs.getDate("fechaDesde"), rs.getDate("fechaHasta"), rs.getFloat("rendimiento"), mineral, rs.getBoolean("eliminado"),rs.getFloat("desperdicio"));
					}
					resultado.add(cereal);
					this.logger.info("cereal encontrado: " + cereal);			
				}			
			} catch (SQLException e) {
				this.logger.error("Error al buscar el cereal. " + e.getMessage());
			}
		} catch (TransaccionException te) {
			this.logger.error("Error al buscar el cereal. " + te.getMessage());
		} finally {
			contexto.liberarConexion();
		}
	
		return resultado;
	}

	@Override
	public boolean guardarTodos(List<Cereal> instancia) {
		
		this.logger.info("Guardo todos los cereales de mi lista");
		ContextoTransaccional contexto = null;
		boolean continuar = true;
		
		try {
			contexto = super.administradorTransaccional.crearContexto(false);
			
			int i = 0;
			for (Cereal cereal : instancia) {
				 System.out.println(i);
				 i ++;
				int resultado = guardarCerealContexto(cereal, contexto.getTransaccionActual().getConexionActiva());
				continuar = resultado > 0;
				 
				if(!continuar) break;
			}
 
			if(!continuar){
				administradorTransaccional.deshacerContexto(contexto);
			}
			administradorTransaccional.actualizarContexto(contexto);
		} catch (TransaccionException e) {
			try {
				administradorTransaccional.deshacerContexto(contexto);
			} catch (TransaccionException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}	
		
		return continuar;
	}

	public List<Cereal> buscarPorMineral(Mineral mineral) {
		
		this.logger.info("Buscando cereal por mineral: " + mineral.getNombre());
		List<Cereal> resultado = new ArrayList<Cereal>();
		
		Cereal cereal = null;
		ContextoTransaccional contexto = null;
		
		try {
			contexto = super.administradorTransaccional.crearContexto(true);		
			
			String query = "SELECT id, codigo, fechaDesde, fechaHasta, rendimiento, mineralPrincipalId, eliminado, tipoCereal, desperdicio, descripcion FROM cereal where mineralPrincipalId = ? and eliminado = 0";
			List<Object> parametros = new ArrayList<Object>();
			
			parametros.add(mineral.getId());
			
			ResultSet rs;
			
			try {				
				rs = this.executeQuery(query, parametros, contexto.getConexionActual());

				while(rs.next()){
											
					if(0 == rs.getInt("tipoCereal")){
							 
						cereal = new CerealFino(rs.getInt("id"), rs.getInt("codigo"), rs.getString("descripcion"), rs.getDate("fechaDesde"), rs.getDate("fechaHasta"), rs.getFloat("rendimiento"), mineral, rs.getBoolean("eliminado"));
					}
					else{
						cereal = new CerealGrueso(rs.getInt("id"), rs.getInt("codigo"), rs.getString("descripcion"), rs.getDate("fechaDesde"), rs.getDate("fechaHasta"), rs.getFloat("rendimiento"), mineral, rs.getBoolean("eliminado"),rs.getFloat("desperdicio"));
					}
					resultado.add(cereal);
					this.logger.info("cereal encontrado: " + cereal);			
				}			
			} catch (SQLException e) {
				this.logger.error("Error al buscar el cereal. " + e.getMessage());
			}
		} catch (TransaccionException te) {
			this.logger.error("Error al buscar el cereal. " + te.getMessage());
		} finally {
			contexto.liberarConexion();
		}
	
		return resultado;
	}
	
	public Cereal buscarPorCodigo(int codigo) {
		
		this.logger.info("Buscando cereal por codigo: " + codigo);
		
		Cereal cereal = null;
		ContextoTransaccional contexto = null;
		
		try {
			contexto = super.administradorTransaccional.crearContexto(true);		
			
			String query = "SELECT id, codigo, fechaDesde, fechaHasta, rendimiento, mineralPrincipalId, eliminado, tipoCereal, desperdicio, descripcion FROM cereal where codigo = ? and eliminado = 0";
			List<Object> parametros = new ArrayList<Object>();
			
			parametros.add(codigo);
			
			ResultSet rs;
			
			try {				
				rs = this.executeQuery(query, parametros, contexto.getConexionActual());

				if(rs.next()){
					
					Mineral mineral = null;
					MineralMapper mineralEntity = new MineralMapper();
					mineral = mineralEntity.buscarPorId(rs.getInt("mineralPrincipalId"));
										
					if(0 == rs.getInt("tipoCereal")){
							 
						cereal = new CerealFino(rs.getInt("id"), rs.getInt("codigo"), rs.getString("descripcion"), rs.getDate("fechaDesde"), rs.getDate("fechaHasta"), rs.getFloat("rendimiento"), mineral, rs.getBoolean("eliminado"));
					}
					else{
						cereal = new CerealGrueso(rs.getInt("id"), rs.getInt("codigo"), rs.getString("descripcion"), rs.getDate("fechaDesde"), rs.getDate("fechaHasta"), rs.getFloat("rendimiento"), mineral, rs.getBoolean("eliminado"),rs.getFloat("desperdicio"));
					}
					this.logger.info("Mineral encontrado: " + mineral);			
				}			
			} catch (SQLException e) {
				this.logger.error("Error al buscar el mineral. " + e.getMessage());
			}
		} catch (TransaccionException te) {
			this.logger.error("Error al buscar el mineral. " + te.getMessage());
		} finally {
			contexto.liberarConexion();
		}
	
		return cereal;

	}
}
